/* 
 * File:   Automata.cpp
 * Author: Dianita
 * 
 * Created on 2 de noviembre de 2013, 03:58 PM
 */

#include "Automata.h"
#include "Utiles.h"
#include <iostream>
#include <sstream>
using namespace std;

Automata::Automata() {
}

//SET Y GET DE LOS ATRIBUTOS

void Automata::setListaEstados(list<Estado> estados) {
    this->listaEstados = estados;
}

list<Estado> Automata::getListaEstados() {
    return this->listaEstados;
}

void Automata::setEstadoInicial(Estado estadoInicial) {
    this->estadoInicial = estadoInicial;
}

Estado Automata::getEstadoInicial() {
    return this->estadoInicial;
}

void Automata::setListaEstadosFinales(list<Estado> estadosFinales) {
    this->listaEstadosFinales = estadosFinales;
}

list<Estado> Automata::getListaEstadosFinales() {
    return this->listaEstadosFinales;
}

void Automata::setAlfabeto(list<Letra> alfabeto) {
    this->alfabeto = alfabeto;
}

list<Letra> Automata::getAlfabeto() {
    return this->alfabeto;
}

void Automata::setTransiciones(list<Transicion> transiciones) {
    this->transiciones = transiciones;
}

list<Transicion> Automata::getTransiciones() {
    return this->transiciones;
}

bool Automata::perteneceAlfabeto(string cadena, list<Letra> alfabeto) {
    Letra letra;
    Utiles utiles;

    for (int i = 0; i < cadena.size(); i++) {
        for (int j = 0; j < alfabeto.size(); j++) {
            letra = utiles.obtenerLetra(alfabeto, j);
            string caracter = utiles.conversorChar_String(cadena[i]);
            if (letra.getNombre().compare(caracter) == 0) {
                break;
            } else {
                if (j == (alfabeto.size() - 1)) {
                    return false;
                }
            }
        }
    }
    return true;
}

Estado Automata::pasarTransicion(list<Transicion> subTransiciones, string letra) {
    Transicion transicion;
    Estado vacia("NULO");
    Utiles utiles;
    for (int i = 0; i < subTransiciones.size(); i++) {
        transicion = utiles.obtenerTransicion(subTransiciones, i);
        if (transicion.getLetra().getNombre() == letra) {
            return transicion.getEstadoFinal();
        }
    }
    return vacia;
}

list<Transicion> Automata::buscaTransiciones(list<Transicion> transiciones, Estado estado) {
    Transicion transicion;
    list<Transicion> auxTransiciones;

    Utiles utiles;
    for (int i = 0; i < transiciones.size(); i++) {
        transicion = utiles.obtenerTransicion(transiciones, i);
        if ((transicion.getEstadoInicial().getNombre().compare(estado.getNombre())) == 0) {
            auxTransiciones.push_back(transicion);
        }
    }
    return auxTransiciones;
}

void Automata::correrAutomata(string cadena) {
    Utiles utiles;
    Estado estadoActual = estadoInicial;
    Estado auxiliar;

    if (perteneceAlfabeto(cadena, alfabeto)) {
        //LA CADENA PERTENECE AL ALFABETO
        for (int i = 0; i < cadena.size(); i++) {
            auxiliar = pasarTransicion(buscaTransiciones(transiciones, estadoActual), utiles.conversorChar_String(cadena[i]));
            if (auxiliar.getNombre() != "NULO") {
                estadoActual = auxiliar;
                if (i == cadena.size() - 1) {
                    //verificar cadena aceptada
                    if (esCadenaAceptada(estadoActual) == 1) {
                        cout << "ES CADENA ACEPTADA \n";
                    } else {
                        cout << "NO ES CADENA ACEPTADA \n";
                    }
                    return;
                }
            } else {
                cout << "NO EXISTE UNA TRANSICION DE: " + estadoActual.getNombre() + " CON " + utiles.conversorChar_String(cadena[i]) + ". PALABRA NO ACEPTADA \n";
                return;
            }
        }
    } else {
        cout << "LA CADENA NO PERTENECE AL ALFABETO \n";
    }
}

bool Automata::esCadenaAceptada(Estado ultimoEstado) {
    Utiles utiles;
    Estado estado;
    for (int i = 0; i < listaEstadosFinales.size(); i++) {
        estado = utiles.obtenerEstado(listaEstadosFinales, i);
        if ((estado.getNombre().compare(ultimoEstado.getNombre())) == 0) {
            return true;
        }
    }
    return false;
}

void Automata::correrAutomataPalabras(list<string> palabras) {
    Utiles utiles;
    Estado estadoActual = estadoInicial;
    Estado auxiliar;
    string cadena;

    for (int j = 0; j < palabras.size(); j++) {
        cadena = utiles.obtenerPalabra(palabras, j);
        if (cadena.size() != 0) {
            if (perteneceAlfabeto(cadena, alfabeto)) {
                //LA CADENA PERTENECE AL ALFABETO
                for (int i = 0; i < cadena.size(); i++) {
                    auxiliar = pasarTransicion(buscaTransiciones(transiciones, estadoActual), utiles.conversorChar_String(cadena[i]));
                    if (auxiliar.getNombre() != "NULO") {
                        estadoActual = auxiliar;
                        if (i == cadena.size() - 1) {
                            //verificar cadena aceptada
                            if (esCadenaAceptada(estadoActual) == 1) {
                                cout << "LA PALABRA " + cadena + " ES ACEPTADA \n";
                            } else {
                                cout << "LA PALABRA " + cadena + " NO ES ACEPTADA \n";
                            }
                            break;
                        }
                    } else {
                        cout << "NO EXISTE UNA TRANSICION DE: " + estadoActual.getNombre() + " CON " + utiles.conversorChar_String(cadena[i]) + ". LA PALABRA " + cadena + " NO ES ACEPTADA \n";
                        break;
                    }
                }
            } else {
                cout << "LA PALABRA " + cadena + " CONTIENE CARACTERES QUE NO PERTENECEN AL ALFABETO \n";
            }
        } else {
            if (esCadenaAceptada(estadoActual) == 1) {
                cout << "LA CADENA VACÍA ES ACEPTADA \n";
            } else {
                cout << "LA CADENA VACÍA NO ES ACEPTADA \n";
            }
        }
        estadoActual = estadoInicial;
    }

}

list<Letra> Automata::generarAlfabeto(list<string> palabras) {
    Utiles utiles;
    list<Letra> letras;
    string pl;
    for (int i = 0; i < palabras.size(); i++) {
        pl = utiles.obtenerPalabra(palabras, i);
        for (int j = 0; j < pl.size(); j++) {
            if ((buscaLetras(utiles.conversorChar_String(pl[j]), letras)) == 0) {
                Letra letra(utiles.conversorChar_String(pl[j]));
                letras.push_back(letra);
            }
        }


    }
    return letras;
}

bool Automata::buscaLetras(string caracter, list<Letra> letras) {

    Utiles utiles;
    Letra letra;
    for (int i = 0; i < letras.size(); i++) {
        letra = utiles.obtenerLetra(letras, i);
        if (letra.getNombre().compare(caracter) == 0) {
            return true;
        }
    }
    return false;
}

void Automata::imprimirAlfabeto(list<Letra> alfabeto) {
    Utiles utiles;
    for (int i = 0; i < alfabeto.size(); i++) {
        cout << utiles.obtenerLetra(alfabeto, i).getNombre()+ " ";
    }
}
